﻿using Newtonsoft.Json.Linq;
using System;
using System.Linq;
using System.Collections.Generic;
using XbmcManager.Types;

namespace XbmcManager.Modules
{
    public class XbmcVideoLibrary
    {
        private XbmcController xbmc;
        private XbmcConnection connection;
        static Random random = new Random();
        private static string TVSHOWID = "tvshowid";
        private static string PROPERTIES = "properties";
        private static string RESULT = "result";

        // Constructor
        internal XbmcVideoLibrary(XbmcController Xbmc, XbmcConnection mConnection)
        {
            this.xbmc = Xbmc;
            this.connection = mConnection;
        }

        /// <summary>
        /// Get a list of all tv shows (series titles) in library.
        /// </summary>
        public List<XbmcTVShow> GetTVShows()
        {
            JObject response = GetTVShowsResponse();

            return ConvertToTVShows(response);
        }

        private JObject GetTVShowsResponse()
        {
            JObject args = new JObject();

            // The fields to be returned
            String[] fields = XbmcTVShow.FIELDS;
            args.Add(new JProperty(PROPERTIES, fields));

            String command = "VideoLibrary.GetTVShows";
            JObject response = connection.SendJson(command, args);
            return response;
        }

        private static List<XbmcTVShow> ConvertToTVShows(JObject response)
        {
            List<XbmcTVShow> tvShows = new List<XbmcTVShow>();

            if (!XbmcController.isError(response))
            {
                JArray items = (JArray)response[RESULT]["tvshows"];

                if (items != null)
                {
                    foreach (JObject item in items)
                    {
                        tvShows.Add(CreateShow(item));
                    }
                }
            }

            return tvShows;
        }

        private static XbmcTVShow CreateShow(JObject item)
        {
            XbmcTVShow show = new XbmcTVShow(item);
            // Replace certain non alpha numeric characters to match to voice commands.
            show.Title = show.Title.Replace("&", "and");
            show.Title = show.Title.Replace(":", "");

            return show;
        }

        /// <summary>
        /// Get a list of seasons of a TV Series
        /// </summary>
        /// <param name="tvShowID"
        /// <returns>An array of all tv shows</returns>
        public List<XbmcSeason> GetSeasons(int tvShowID)
        {
            JObject response = GetSeasonsResponse(tvShowID);

            return ConvertToSeasons(response);
        }

        private JObject GetSeasonsResponse(int tvShowID)
        {
            JObject args = new JObject();
            args.Add(new JProperty(TVSHOWID, tvShowID));

            // The fields to be returned
            String[] fields = XbmcSeason.FIELDS;
            args.Add(new JProperty(PROPERTIES, fields));

            String command = "VideoLibrary.GetSeasons";
            JObject response = connection.SendJson(command, args);
            return response;
        }

        private static List<XbmcSeason> ConvertToSeasons(JObject response)
        {
            List<XbmcSeason> seasons = new List<XbmcSeason>();

            if (!XbmcController.isError(response))
            {
                JArray items = (JArray)response[RESULT]["seasons"];

                if (items != null)
                {
                    foreach (JObject item in items)
                    {
                        seasons.Add(new XbmcSeason(item));
                    }
                }
            }

            return seasons;
        }

        /// <summary>
        /// Get a list of all episodes for a TV Series
        /// </summary>
        /// <param name="tvShowID"></param>
        /// <returns>An array of all tv shows</returns>
        public List<XbmcEpisode> GetEpisodesByTVShow(int tvShowID)
        {
            JObject response = GetEpisodesResponse(tvShowID);

            return ConvertToEpisodes(response);
        }

        private JObject GetEpisodesResponse(int tvShowID)
        {
            JObject args = new JObject();
            args.Add(new JProperty(TVSHOWID, tvShowID));

            // The fields to be returned
            String[] fields = XbmcEpisode.FIELDS;
            args.Add(new JProperty(PROPERTIES, fields));

            String command = "VideoLibrary.GetEpisodes";
            JObject response = connection.SendJson(command, args);
            return response;
        }

        /// <summary>
        /// Get a random episode of a TV Series
        /// </summary>
        /// <param name="tvShowID"></param>
        /// <returns>Random Episode of a TV Series</returns>
        public XbmcEpisode GetRandomEpisodeByTVShow(int tvShowID)
        {
            List<XbmcEpisode> episodes = GetEpisodesByTVShow(tvShowID);

            int index = random.Next(episodes.Count());

            XbmcEpisode randomEpisode = episodes[index];

            return randomEpisode;
        }

        /// <summary>
        /// Get next unwatched episode of a TV Series
        /// </summary>
        /// <param name="tvShowID"></param>
        /// <returns>Next Unwatched Episode of a TV Series. If all have been watched return last episode.</returns>
        public XbmcEpisode GetNextUnwatchedEpisodeByTVShow(int tvShowID)
        {
            List<XbmcEpisode> episodes = GetEpisodesByTVShow(tvShowID);
            
            var episodeQuery = from e in episodes
                               where e.PlayCount == 0
                               orderby e.EpisodeTitle
                               select e;

            XbmcEpisode episode;
            episode = episodeQuery.FirstOrDefault();

            return episode;
        }

        /// <summary>
        /// Get a list of episodes of a TV Series by season 
        /// </summary>
        /// <param name="season"></param>
        /// <param name="tvShowID"></param>
        /// <returns>An array of all tv shows</returns>
        public List<XbmcEpisode> GetEpisodesBySeason(int tvShowID, int season)
        {
            JObject response = GetEpisodesResponse(tvShowID, season);

            return ConvertToEpisodes(response);
        }

        private JObject GetEpisodesResponse(int tvShowID, int season)
        {
            JObject args = new JObject();
            args.Add(new JProperty(TVSHOWID, tvShowID));
            args.Add(new JProperty("season", season));

            // The fields to be returned
            String[] fields = XbmcEpisode.FIELDS;
            args.Add(new JProperty(PROPERTIES, fields));

            String command = "VideoLibrary.GetEpisodes";
            JObject response = connection.SendJson(command, args);
            return response;
        }

        private static List<XbmcEpisode> ConvertToEpisodes(JObject response)
        {
            List<XbmcEpisode> episodes = new List<XbmcEpisode>();

            if (!XbmcController.isError(response))
            {
                JArray items = (JArray)response[RESULT]["episodes"];

                if (items != null)
                {
                    foreach (JObject item in items)
                    {
                        episodes.Add(new XbmcEpisode(item));
                    }
                }
            }

            return episodes;
        }

        /// <summary>
        /// Get a list of all movies in library.
        /// </summary>
        /// <returns>An array of all movies</returns>
        public List<XbmcMovie> GetMovies()
        {
            JObject response = GetMoviesResponse();

            return ConvertToMovies(response);
        }

        private JObject GetMoviesResponse()
        {
            JObject args = new JObject();

            // The fields to be returned
            String[] fields = XbmcMovie.FIELDS;
            args.Add(new JProperty(PROPERTIES, fields));

            String command = "VideoLibrary.GetMovies";
            JObject response = connection.SendJson(command, args);
            return response;
        }

        private static List<XbmcMovie> ConvertToMovies(JObject response)
        {
            List<XbmcMovie> movies = new List<XbmcMovie>();

            if (!XbmcController.isError(response))
            {
                JArray items = (JArray)response[RESULT]["movies"];

                if (items != null)
                {
                    foreach (JObject item in items)
                    {
                        movies.Add(new XbmcMovie(item));
                    }
                }
            }

            return movies;
        }

        public void Scan()
        {
            this.connection.SendJson("VideoLibrary.Scan");
        }

    }
}
